package com.google.wave.extensions.code.eval;

import java.util.Collections;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.cache.Cache;
import javax.cache.CacheException;
import javax.cache.CacheFactory;
import javax.cache.CacheManager;

/**
 * {@code CachingCodeEvaluator} decorates an existing {@link
 * CodeEvaluator} and adds caching of the results via {@code
 * javax.cache}.
 *
 * @author schwardo@google.com (Don Schwarz)
 */
class CachingCodeEvaluator implements CodeEvaluator {
    private static final Logger logger =
	Logger.getLogger(CachingCodeEvaluator.class.getName());

    private final CodeEvaluator parent;
    private final Cache cache;

    public CachingCodeEvaluator(CodeEvaluator parent) {
	this.parent = parent;
        this.cache = createCache();
    }

    public CodeResult eval(String expr) {
        if (cache == null) {
          return parent.eval(expr);
        }

        CodeResult result = (CodeResult) cache.get(expr);
	if (result == null) {
	    result = parent.eval(expr);
	    logger.info("Caching value for " + expr);
	    cache.put(expr, result);
	} else {
	    logger.info("Using cached value for " + expr);
	}
	return result;
    }

    private static Cache createCache() {
        try {
            CacheFactory cacheFactory = CacheManager.getInstance().getCacheFactory();
            return cacheFactory.createCache(Collections.emptyMap());
        } catch (CacheException ex) {
            logger.log(Level.WARNING, "Could not create cache:", ex);
            return null;
        }
    }
}
